// 版权所有2011 Go作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package binary

// 此文件实现64位整数的“可变”编码。
// 编码是：
// -无符号整数一次序列化7位，从
// 最低有效位
// -每个输出字节中的最高有效位（msb）指示是否存在
// 是连续字节（msb=1）
// -有符号整数使用“之字形”映射到无符号整数
// 编码：正值x写为2*x+0，负值
// 写为2*（^x）+1；也就是说，负数是互补的
// 是否补码以0位编码。
// None
// 设计说明：
// 64位值最多需要10个字节。这种编码可能是错误的
// 更密集：一个完整的64位值需要一个额外的字节来容纳位63。
// 相反，前一个字节的msb可用于保存位63，因为我们
// 知道不能超过64位。这是一个微不足道的改进和改进
// 将最大编码长度减少到9字节。然而，它打破了传统
// 表示msb始终是“延续位”，因此使
// 与较大数字（如128位）的可变编码不兼容的格式。

import (
	"errors"
	"io"
)

// MaxVarinterNN是变量编码的N位整数的最大长度。
const (
	MaxVarintLen16 = 3
	MaxVarintLen32 = 5
	MaxVarintLen64 = 10
)

// PutUvarint将uint64编码为buf并返回写入的字节数。
// 如果缓冲区太小，PutUvarint就会恐慌。
func PutUvarint(buf []byte, x uint64) int {
	i := 0
	for x >= 0x80 {
		buf[i] = byte(x) | 0x80
		x >>= 7
		i++
	}
	buf[i] = byte(x)
	return i + 1
}

// Uvarint从buf解码uint64并返回该值和
// 读取的字节数（>0）。如果发生错误，则该值为0
// 字节数n<=0表示：
// None
// n==0:buf太小
// n<0：大于64位的值（溢出）
// 和-n是读取的字节数
// None
func Uvarint(buf []byte) (uint64, int) {
	var x uint64
	var s uint
	for i, b := range buf {
		if i == MaxVarintLen64 {
			// 捕获字节读取超过maxVarintern64。
			// 见问题https:
			return 0, -(i + 1) // 溢流
		}
		if b < 0x80 {
			if i == MaxVarintLen64-1 && b > 1 {
				return 0, -(i + 1) // 溢流
			}
			return x | uint64(b)<<s, i + 1
		}
		x |= uint64(b&0x7f) << s
		s += 7
	}
	return 0, 0
}

// PutVarint将int64编码为buf并返回写入的字节数。
// 如果缓冲区太小，PutVarint将死机。
func PutVarint(buf []byte, x int64) int {
	ux := uint64(x) << 1
	if x < 0 {
		ux = ^ux
	}
	return PutUvarint(buf, ux)
}

// Varint从buf解码int64并返回该值和
// 读取的字节数（>0）。如果发生错误，则该值为0
// 并且字节数n<=0，具有以下含义：
// None
// n==0:buf太小
// n<0：大于64位的值（溢出）
// 和-n是读取的字节数
// None
func Varint(buf []byte) (int64, int) {
	ux, n := Uvarint(buf) // 确定以在出现错误时继续
	x := int64(ux >> 1)
	if ux&1 != 0 {
		x = ^x
	}
	return x, n
}

var overflow = errors.New("binary: varint overflows a 64-bit integer")

// ReadUvarint从r中读取编码的无符号整数，并将其作为uint64返回。
func ReadUvarint(r io.ByteReader) (uint64, error) {
	var x uint64
	var s uint
	for i := 0; i < MaxVarintLen64; i++ {
		b, err := r.ReadByte()
		if err != nil {
			return x, err
		}
		if b < 0x80 {
			if i == MaxVarintLen64-1 && b > 1 {
				return x, overflow
			}
			return x | uint64(b)<<s, nil
		}
		x |= uint64(b&0x7f) << s
		s += 7
	}
	return x, overflow
}

// ReadVarint从r读取编码的有符号整数，并将其作为int64返回。
func ReadVarint(r io.ByteReader) (int64, error) {
	ux, err := ReadUvarint(r) // 确定以在出现错误时继续
	x := int64(ux >> 1)
	if ux&1 != 0 {
		x = ^x
	}
	return x, err
}
